#include "condition_check.hh"
#include <stdexcept>
#include <boost/format.hpp>
#include <boost/logic/tribool.hpp>

using boost::tribool;
using boost::indeterminate;

bool check_condition(const Adventure &adv, const std::vector<Cmd> &conditions) {
  if(conditions.empty()) return true;
  bool total = true;
  bool negate = false;
  tribool ret = indeterminate;
  /* Complicated loop: check all conditions, but if total is false (as
     we currently do an AND for all conditions then break off
     immediately.
  */
  for(unsigned int i = 0; (i < conditions.size()) && total; ++i) {
    ret = indeterminate;
    Cmd ccmd = conditions[i];
    switch(ccmd.c) {
    case '!': //negate *next* condition
      if(negate) throw std::logic_error("double negation?");
      negate = true;
      break;
    case 'l': //Check location
      ret = ccmd.p1 == adv.here;
      break;
    case 'a': //Object 1 avail
      ret = (adv.objects[adv.obj1].pos == adv.here) || (adv.objects[adv.obj1].pos == POS_CARRIED);
      break;
    case 'A': //Object ? avail
      ret = (adv.objects[ccmd.p1].pos == adv.here) || (adv.objects[ccmd.p1].pos == POS_CARRIED);
      break;
    case 'h': //Object 1 here?
      ret = adv.objects[adv.obj1].pos == adv.here;
      break;
    case 'H': //Object ? here?
      ret = adv.objects[ccmd.p1].pos == adv.here;
      break;
    case 'c': //Carrying object 1
      ret = adv.objects[adv.obj1].pos == POS_CARRIED;
      break;
    case 'C': //Carrying object ?
      ret = adv.objects[ccmd.p1].pos == POS_CARRIED;
      break;
    case 'Y': //Object ? nowhere?
      ret = adv.objects[ccmd.p1].pos == POS_NOWHERE;
      break;
    case -'Y': //Object ? destroyed?
      ret = adv.objects[ccmd.p1].pos == POS_KILLED;
      break;
    default:
      throw std::runtime_error(str(boost::format("unknown condition %d $%X '%c'") % ccmd.c % ccmd.c % static_cast<char>(ccmd.c)));
    }
    if(!indeterminate(ret)) {
      if(negate) {
	ret = !ret;
	negate = false;
      }
      total = total && ret;
    }
  }
  if(indeterminate(ret)) throw std::logic_error("last condition has indeterminate result");
  return total;
}
